package ru.amse.stroganova.ui.tool;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;

import javax.swing.AbstractAction;
import javax.swing.ImageIcon;

import ru.amse.stroganova.algorythms.DFS;
import ru.amse.stroganova.algorythms.FordFalkersonAlgorythm;
import ru.amse.stroganova.presentation.VertexPresentation;
import ru.amse.stroganova.ui.GraphComponent;
import ru.amse.stroganova.ui.tool.state.SelectionState;
import ru.amse.stroganova.ui.tool.state.ToolState;

class MaxFlowSelectionTool extends Tool {
	
	private final GraphComponent component;
	
	private ToolState currentMaxFlowState;
	
	private ToolState currentState;
	
	private VertexPresentation sourcePresentation;
	
	private final ToolState sourceVertexSelectionState = new ToolState() {
		
		@Override
		public void mouseClicked(MouseEvent e) {
			VertexPresentation selectedVertex = component.getGraphElementSelection().getVertex(e.getPoint());
			if (selectedVertex == null) {
				return;
			}
			sourcePresentation = selectedVertex;
			component.getGraphElementMarker().markVertex(selectedVertex);
			component.getGraphElementMarker().markVertices(new DFS(component.getGraphPresentation().getGraph()).findReachableVertices(selectedVertex.getVertex()));
			component.getAlgorythmActionsFactory().meaasgeActive("Select sink vertex from reachable ones...", false);
			currentMaxFlowState = sinkVertexSelectionState;
		}
		
		@Override
		public void mouseMoved(MouseEvent e) {
			component.getGraphElementMarker().unmarkVertices();
			VertexPresentation selectedVertex = component.getGraphElementSelection().getVertex(e.getPoint());
			if (selectedVertex != null) {
				component.getGraphElementMarker().markVertices(new DFS(component.getGraphPresentation().getGraph()).findReachableVertices(selectedVertex.getVertex()));
			}
		}
	};
	
	private final ToolState sinkVertexSelectionState = new ToolState() {
		
		@Override
		public void mouseClicked(MouseEvent e) {
			component.getGraphElementMarker().unmarkVertices();
			component.getGraphElementMarker().unmarkEdges();
			component.getGraphElementMarker().markVertex(sourcePresentation);
			VertexPresentation selectedVertex = component.getGraphElementSelection().getVertex(e.getPoint());
			if (selectedVertex == null) {
				return;
			}
			FordFalkersonAlgorythm fordFalkerson = new FordFalkersonAlgorythm(component.getGraphPresentation().getGraph(), sourcePresentation.getVertex(), selectedVertex.getVertex());
			component.getAlgorythmActionsFactory().messageUnactive();
			if (fordFalkerson.hasNegativeCapacities()) {
				component.getAlgorythmActionsFactory().meaasgeActive(fordFalkerson.getErrorMessage(), true);
				component.getEditingActionsFactory().getSelectAction().putValue(AbstractAction.SMALL_ICON, new ImageIcon(ClassLoader.getSystemResource("img/select.gif")));
				component.setTool(component.getToolFactory().getSelectTool());
				return;
			}
			component.getGraphElementMarker().markVertex(selectedVertex);
			component.getGraphElementMarker().markVertexWithData(selectedVertex.getVertex(), fordFalkerson.getMaximumFlowSize());
			component.getGraphElementMarker().markEdges(fordFalkerson.getMaximumFlow().keySet(), false);
			component.getGraphElementMarker().markEdgesWithData(fordFalkerson.getMaximumFlow());
			component.getEditingActionsFactory().getSelectAction().putValue(AbstractAction.SMALL_ICON, new ImageIcon(ClassLoader.getSystemResource("img/select.gif")));
			component.setTool(component.getToolFactory().getSelectTool());
		}
		
		@Override
		public void mouseMoved(MouseEvent e) {
			component.getGraphElementMarker().unmarkEdges();
			VertexPresentation selectedVertex = component.getGraphElementSelection().getVertex(e.getPoint());
			if (selectedVertex != null) {
				component.getGraphElementMarker().markEdges(new DFS(component.getGraphPresentation().getGraph()).findAllPaths(sourcePresentation.getVertex(), selectedVertex.getVertex()), false);
			}
		}
	};
	
	MaxFlowSelectionTool(GraphComponent component) {
		this.component = component;
		currentState = new SelectionState(component, this);
		currentMaxFlowState = sourceVertexSelectionState;
	}
	
	@Override
	public void mousePressed(MouseEvent e) {
		currentState.mousePressed(e);
	}
	
	@Override
	public void mouseClicked(MouseEvent e) {
		currentMaxFlowState.mouseClicked(e);
		currentState.mouseClicked(e);
	}
	
	@Override
	public void mouseDragged(MouseEvent e) {
		currentState.mouseDragged(e);
	}
	
	@Override
	public void mouseMoved(MouseEvent e) {
		currentMaxFlowState.mouseMoved(e);
	}
	
	@Override
	public void mouseReleased(MouseEvent e) {
		currentState.mouseReleased(e);
	}
	
	@Override
	public void setState(ToolState state) {
		currentState = state;
	}
	
	@Override
	public void paint(Graphics g, Color backgroundColor) {
		currentState.paint(g, backgroundColor);
	}
	
	/*package*/ void returnToInitialState() {
		component.getAlgorythmActionsFactory().meaasgeActive("Select source vertex...", false);
		currentState = new SelectionState(component, this);
		currentMaxFlowState = sourceVertexSelectionState;
	}

}
